home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1996 #15
/
Monster Media Number 15 (Monster Media)(July 1996).ISO
/
math
/
alged34.zip
/
ALGEDSRC.ZIP
/
ALGPOLY.C
< prev
next >
Wrap
C/C++ Source or Header
|
1996-06-06
|
16KB
|
540 lines
/*--------------------------------------------------------------------
Alged: Algebra Editor henckel@vnet.ibm.com
Copyright (c) 1994 John Henckel
Permission to use, copy, modify, distribute and sell this software
and its documentation for any purpose is hereby granted without fee,
provided that the above copyright notice appear in all copies.
*/
#include "alged.h"
/*-----------------------------------------------------------------
make-tree convert a table of coefficients to a node tree.
Note
the coefficients are REUSED (NOT copied), so don't free them.
*/
node *maketree(node **coef, int sz, node *base) {
int i;
node *p,*tmp;
p = coef[0];
for (i=1; i<sz; ++i) {
if (coef[i]->kind==NUM && !coef[i]->value) {
freenode(coef[i]); /* throw away zeros */
}
else {
tmp = p;
p = newoper(ADD);
p->lf = tmp;
p->rt = tmp = newoper(MUL);
tmp->lf = coef[i]; /* add coef[i]*base^i */
if (i>1) {
tmp->rt = newoper(EXP);
tmp->rt->lf = deepcopy(base);
tmp->rt->rt = newnum(i);
}
else tmp->rt = deepcopy(base);
}
}
return p;
}
/*-----------------------------------------------------------------
looks inside 'a' for any expression b or b^N.
if found, it changes it to a 1 (ONE) and returns the exponent.
Note, if N is not an integer (it's a fraction or expression)
then findbase ignores it.
When findbase returns 0, then you can assume 'a' is unchanged.
*/
int findbase(node *a, node *b) {
int i,x=1;
if (equal(a,b) || /* any expression */
a->kind==EXP && a->rt->kind==NUM && /* EXPONENTS */
(x = a->rt->value, whole(x)) &&
x >=0 && equal(a->lf,b)) {
movenode(a,newnum(1));
return x;
}
if (a->kind==MUL) { /* recurse on MULTIPLY */
x = findbase(a->lf,b);
if (x) return x;
x = findbase(a->rt,b);
return x;
}
return 0;
}
/*-----------------------------------------------------------------
add entry to coef table grow and init table
*/
#define addcoef(k,a) do { \
node *tmp; \
if (sz<=i) { \
coef = realloc((void*)coef,(i+1)*sizeof*coef); \
for ( ; sz<=i; ++sz) \
coef[sz] = newnum(0); \
} \
tmp = coef[i]; \
coef[i] = newoper(k); \
coef[i]->lf = tmp; \
coef[i]->rt = a; \
} while(0)
/*-----------------------------------------------------------------
MAKETABLE convert a tree to a table of coefficients which is indexed
by the power of a given base. For example, a*x^2 + 3*x - b would be
0 -> 0 - b
1 -> 0 + 3
2 -> 0 + a
the size returned is the index of the last non-zero coefficient + 1
Note:
the tree, p, is expected to have correct association.
the coefficients always have a leading zero.
the tree is not altered or referred to by the table.
on return, you are guaranteed that result[i]->kind is one of NUM,
ADD, SUB and if it is NUM then it is zero.
*/
node **maketable(node *base, node *p, int *size) {
node *a;
int i,sz;
node **coef;
coef = malloc(sizeof*coef); /* initial size = 1 */
checknull(coef);
*coef = newnum(0);
sz = 1;
a = deepcopy(p); /* make a working copy */
while (1) {
i = findbase(a,base);
if (!i && aop(a->kind)) {
i = findbase(a->rt,base);
addcoef(a->kind,a->rt);
}
else {
addcoef(ADD,a);
break;
}
a = a->lf;
}
*size = sz;
return coef;
}
/*-----------------------------------------------------------------
polynomial long division
base is the expression on which the division is done (e.g. x)
nm and dn are numerator and denominator
returns:
a new tree if success, else returns NULL
*/
node *polydiv(node *base, node *nm, node *dn) {
node **num,**den,**quo,**rem;
int szn,szd,szq,szr;
int i,j;
node *tmp,*p;
num = maketable(base,nm,&szn);
den = maketable(base,dn,&szd);
/* If degree of numerator is less than denominator, or
if the denominator does not contain base, then return failure */
if (szn < szd || szd < 2) {
for (i=0; i<szn; ++i) freetree(num[i]);
for (i=0; i<szd; ++i) freetree(den[i]);
free(num); free(den);
return NULL;
}
szq = szn-szd+1;
quo = malloc(szq*sizeof*quo);
checknull(quo);
szr = szd-1;
rem = malloc(szr*sizeof*rem);
checknull(rem);
/* Divide every coefficient by leading coeff in denominator */
p = den[szd-1];
if (!(p->kind==ADD && p->rt->kind==NUM && p->rt->value==1.0)) {
for (i=0; i<szn; ++i) {
if (num[i]->kind != NUM) { twirl();
tmp = num[i];
num[i] = newoper(DIV);
num[i]->lf = tmp;
num[i]->rt = deepcopy(p);
}
}
for (i=0; i<szd-1; ++i) {
if (den[i]->kind != NUM) { twirl();
tmp = den[i];
den[i] = newoper(DIV);
den[i]->lf = tmp;
den[i]->rt = deepcopy(p);
}
}
}
/* Construct the coefficients of the quotient */
for (i=1; i<=szq; ++i) {
quo[szq-i] = deepcopy(num[szn-i]);
for (j=1; j<i; ++j) if (i-j < szd) { twirl();
tmp = quo[szq-i];
quo[szq-i] = newoper(SUB);
quo[szq-i]->lf = tmp;
quo[szq-i]->rt = tmp = newoper(MUL);
tmp->lf = deepcopy(den[szd-i+j-1]);
tmp->rt = deepcopy(quo[szq-j]);
}
}
/* Construct the coefficients of the remainder */
for (i=0; i<szr; ++i) {
rem[i] = deepcopy(num[i]);
for (j=0; j<=i; ++j) if (i-j < szq) { twirl();
tmp = rem[i];
rem[i] = newoper(SUB);
rem[i]->lf = tmp;
rem[i]->rt = tmp = newoper(MUL);
tmp->lf = deepcopy(den[j]);
tmp->rt = deepcopy(quo[i-j]);
}
}
/* Convert the quo and rem tables into a node tree */
p = newoper(ADD);
p->rt = newoper(DIV);
p->rt->lf = maketree(rem,szr,base);
p->rt->rt = deepcopy(dn);
p->lf = maketree(quo,szq,base);
/* Calculate remainder trivial stuff */
while (calcnode(p->rt,1));
/* Clean up and return */
for (i=0; i<szn; ++i) freetree(num[i]);
for (i=0; i<szd; ++i) freetree(den[i]);
free(num);
free(quo);
free(rem);
free(den);
return p;
}
/*-----------------------------------------------------------------
polycoef - collect the coefficients of a polynomial
*/
void polycoef(node *base, node *p) {
node **coef;
int sz;
int i;
if (!p || !base || p->kind==EQU || base->kind==EQU) return;
coef = maketable(base,p,&sz);
if (sz < 2) {
if (sz) freetree(coef[0]);
free(coef);
return;
}
for (i=0; i<sz; ++i) /* calculate the coefficients */
while (calcnode(coef[i],1));
movenode(p,maketree(coef,sz,base)); /* replace p */
free(coef);
}
/*-----------------------------------------------------------------
use quadratic equation to factor a degree-2 polynomial
2 2
2 b + sqrt(b - 4ac) b - sqrt(b - 4ac)
ax + bx + c ==> a(x + -----------------) (x + -----------------)
2a 2a
*/
void quadratic(node *base,node *p) {
node **coef,*a;
int sz;
int i;
coef = maketable(base,p,&sz);
if (sz != 3) {
for (i=0; i<sz; ++i) freetree(coef[i]);
free(coef);
return;
}
/* Construct the two binomials p = (ax + u)(x + v) */
a = newoper(ADD);
a->lf = deepcopy(coef[1]); /* b */
a->rt = newoper(EXP);
a->rt->lf = newoper(SUB);
a->rt->lf->lf = newoper(EXP); /* b^2 */
a->rt->lf->lf->lf = deepcopy(coef[1]);
a->rt->lf->lf->rt = newnum(2);
a->rt->lf->rt = newoper(MUL); /* 4ac */
a->rt->lf->rt->lf = newoper(MUL);
a->rt->lf->rt->lf->lf = newnum(4);
a->rt->lf->rt->lf->rt = deepcopy(coef[2]);
a->rt->lf->rt->rt = deepcopy(coef[0]);
a->rt->rt = newnum(0.5);
movenode(p,newoper(MUL));
p->lf = newoper(ADD);
p->lf->lf = newoper(MUL); /* ax */
p->lf->lf->lf = deepcopy(coef[2]);
p->lf->lf->rt = deepcopy(base);
p->lf->rt = newoper(DIV);
p->lf->rt->lf = a;
p->lf->rt->rt = newnum(2);
p->rt = newoper(ADD);
p->rt->lf = deepcopy(base);
p->rt->rt = newoper(DIV);
p->rt->rt->lf = deepcopy(a);
p->rt->rt->lf->kind = SUB;
p->rt->rt->rt = newoper(MUL); /* 2a */
p->rt->rt->rt->lf = newnum(2);
p->rt->rt->rt->rt = deepcopy(coef[2]);
while(calcnode(p->lf->lf->lf,1));
while(calcnode(p->lf->rt,1));
while(calcnode(p->rt->rt,1));
for (i=0; i<sz; ++i) freetree(coef[i]);
free(coef);
}
/*-----------------------------------------------------------------
use cubic equation to factor a degree-3 polynomial
*/
void cubic(node *base,node *pol) {
node **coef;
int sz;
int i,k=1;
node *a3,*a,*b,*c,*A,*B,*Q,*p,*q,*y1,*y2,*y3,*r;
coef = maketable(base,pol,&sz);
if (sz != 4) {
for (i=0; i<sz; ++i) freetree(coef[i]);
free(coef);
return;
}
a = cons(deepcopy(coef[2]),DIV,deepcopy(coef[3]));
b = cons(deepcopy(coef[1]),DIV,deepcopy(coef[3]));
c = cons(deepcopy(coef[0]),DIV,deepcopy(coef[3]));
while(calcnode(a,k));
while(calcnode(b,k));
while(calcnode(c,k));
a3= cons(deepcopy(a),DIV,newnum(3));
p = cons(deepcopy(b),SUB,cons(deepcopy(a),MUL,deepcopy(a3)));
q = cons(newnum(2),MUL,cons(deepcopy(a3),EXP,newnum(3)));
q = cons(q,SUB,cons(deepcopy(a3),MUL,deepcopy(b)));
q = cons(q,ADD,deepcopy(c));
while(calcnode(p,k));
while(calcnode(q,k));
Q = cons(cons(deepcopy(p),DIV,newnum(3)),EXP,newnum(3));
Q = cons(Q,ADD,cons(cons(deepcopy(q),DIV,newnum(2)),EXP,newnum(2)));
while(calcnode(Q,k));
if (Q->kind!=NUM || Q->value >= 0) { /* not "irreducible" case */
A = cons(deepcopy(q),DIV,newnum(-2));
A = cons(A,ADD,cons(deepcopy(Q),EXP,newnum(0.5)));
A = cons(A,EXP,newnum(1.0/3.0));
B = deepcopy(A);
B->lf->kind = SUB;
while(calcnode(A,k));
while(calcnode(B,k));
y1 = cons(deepcopy(A),ADD,deepcopy(B));
y2 = cons(deepcopy(y1),DIV,newnum(2));
y2->lf->kind = SUB;
y2 = cons(y2,MUL,cons(newvar("i"),MUL,cons(newnum(3),EXP,newnum(0.5))));
y2 = cons(cons(deepcopy(y1),DIV,newnum(-2)),ADD,y2);
y3 = deepcopy(y2);
y3->kind = SUB;
while(calcnode(y1,k));
while(calcnode(y2,k));
while(calcnode(y3,k));
r = deepcopy(coef[3]);
r = cons(r,MUL,cons(deepcopy(base),SUB,cons(y1,SUB,deepcopy(a3))));
r = cons(r,MUL,cons(deepcopy(base),SUB,cons(y2,SUB,deepcopy(a3))));
r = cons(r,MUL,cons(deepcopy(base),SUB,cons(y3,SUB,deepcopy(a3))));
movenode(pol,r);
freetree(A);
freetree(B);
}
for (i=0; i<sz; ++i) freetree(coef[i]);
freetree(a);
freetree(b);
freetree(c);
freetree(a3);
freetree(Q);
freetree(p);
freetree(q);
free(coef);
}
/*-----------------------------------------------------------------
next factor, returns the ith factor of an expression.
it is a new nodetree.
*/
node *nextfact(node *p,int i) {
int j;
double k;
if (i<1) return newnum(1); /* everything has factor 1 */
if (p->kind==NUM && (k = fabs(p->value), whole(k))) {
if (k==1) return NULL; /* don't return 1 twice */
for (j=2; j<=maxrat && j*2<=k; ++j)
if (fmod(k,j)==0 && !--i)
return newnum(j);
}
else if (p->kind==MUL) {
while (i>2 && p->kind==MUL) {
p=p->lf; i-=2;
}
if (i==2 && p->kind==MUL)
return deepcopy(p->rt);
}
if (i==1) return deepcopy(p);
return NULL;
}
/*-----------------------------------------------------------------
check root
returns the new quotient on success, else null;
*/
node *checkroot(node *base, node *p, node *den) {
node *ans;
twirl();
ans = polydiv(base,p,den);
if (!ans) return NULL;
if (ans->kind==ADD) { /* always true!! */
while (distribute(ans->rt));
simplify(ans->rt);
while (calcnode(ans->rt,0));
simplify(ans->rt);
if (ans->rt->kind==NUM && ans->rt->value==0) /* success!! */
return ans;
}
freetree(ans);
return NULL;
}
/*-----------------------------------------------------------------
factor a polynomial using rational roots
Note: this doesn't work unless all the coefficients are
integers, or at least, not some form of quotient like (a*x/b).
*/
void factrpoly(node *base,node *p) {
node **coef,*a,*b,*q,*dn,*nm,*r;
int sz;
int i,j,n;
coef = maketable(base,p,&sz);
if (sz < 3) {
for (i=0; i<sz; ++i) freetree(coef[i]);
free(coef);
return;
}
/* For every possible rational root, check it for divisibility */
// debug(coef[0]); debug(coef[sz-1]);
if (coef[0]->kind!=NUM) {
if (coef[0]->rt->kind==DIV && // coef is (0 + a/b) rational number
(a = coef[0]->rt->lf)->kind == NUM &&
(b = coef[0]->rt->rt)->kind == NUM &&
coef[sz-1]->kind!=NUM) {
coef[sz-1]->kind = MUL;
coef[sz-1]->lf = b; // move b to the leading coef
if (coef[0]->kind==SUB)
a->value = -a->value;
freenode(coef[0]->lf);
freenode(coef[0]->rt);
freenode(coef[0]);
coef[0] = a;
}
else {
while (calcnode(coef[0],0));
if (coef[0]->kind!=NUM) {
// primefact(coef[0]); this may cause trouble with exponents
// while (distribute_c(coef[0])); // y^(2*2) = y^2 * y^2
while (exexpand(coef[0]));
while (nosubdiv(coef[0]));
while (distribute_c(coef[0])); // (xy)^-1 = x^-1 * y^-1
while (fixassoc(coef[0]));
}
}
}
while (calcnode(coef[sz-1],0));
// debug(coef[0]); debug(coef[sz-1]);
nm = deepcopy(p); /* initialize numerator */
n = 2; /* n is factor counter */
r = NULL; /* intialize the list of factors */
for (i=0; n<sz; ++i) {
b = nextfact(coef[sz-1],i); /* get next factor */
if (!b) break;
for (j=0; n<sz;) {
a = nextfact(coef[0],j); /* next factor */
if (!a) break;
/*-----------------------------------------------------------------
check roots a/b, -a/b, ia/b, -ia/b
*/
dn = cons(deepcopy(base),SUB,cons(a,DIV,deepcopy(b)));
simplify(dn->rt); /* twice for good luck */
#define DO_CHECK \
simplify(dn->rt); \
q = checkroot(base,nm,dn); \
if (q) { \
r = cons(r,MUL,dn);\
freetree(nm); \
nm = q; \
while(distribute(nm)); \
simplify(nm); \
simplify(nm); \
++n; \
continue; \
}
DO_CHECK
dn->rt = cons(dn->rt,MUL,newnum(-1));
DO_CHECK
dn->rt = cons(dn->rt,MUL,newvar("i"));
DO_CHECK
dn->rt = cons(dn->rt,MUL,newnum(-1));
DO_CHECK
freetree(dn);
++j;
}
freetree(b);
}
if (n > 2) {
r = cons(r,MUL,nm);
movenode(p,r); /* replace p with r */
}
for (i=0; i<sz; ++i) freetree(coef[i]);
free(coef);
return;
}